#include "client.hpp"
extern Zhuce login_msg;
extern time_t now;
void splitString(const char *pstrs, const char *delimiter, char *tokens[], int max_tokens, int *pcount)
{
    int token_count = 0;
    char *token = strtok((char *)pstrs, delimiter);
    while (token != nullptr && token_count < max_tokens - 1)
    {
        char *pstr = (char *)calloc(1, strlen(token) + 1);
        strcpy(pstr, token);
        tokens[token_count++] = pstr;
        token = strtok(nullptr, delimiter);
    }
    tokens[token_count] = nullptr;
    *pcount = token_count;
}
void freeStrs(char *pstrs[], int count)
{
    for (int i = 0; i < count; i++)
    {
        free(pstrs[i]);
    }
}
int tcpConnect(const char *ip, uint16_t port)
{
    int clientfd = socket(AF_INET, SOCK_STREAM, 0);
    if (clientfd < 0)
    {
        perror("socket");
        return -1;
    }
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = inet_addr(ip);
    int ret = connect(clientfd, (struct sockaddr *)&server, sizeof(server));
    if (ret < 0)
    {
        perror("connect");
        close(clientfd);
        return -1;
    }
    return clientfd;
}
int getCommandType(const char *str)
{
    if (!strcmp(str, "pwd"))
        return CMD_TYPE_PWD;
    else if (!strcmp(str, "ls"))
        return CMD_TYPE_LS;
    else if (!strcmp(str, "cd"))
        return CMD_TYPE_CD;
    else if (!strcmp(str, "mkdir"))
        return CMD_TYPE_MKDIR;
    else if (!strcmp(str, "rmdir"))
        return CMD_TYPE_RMDIR;
    else if (!strcmp(str, "puts"))
        return CMD_TYPE_PUTS;
    else if (!strcmp(str, "gets"))
        return CMD_TYPE_GETS;
    else
        return CMD_TYPE_NOTCMD;
}
int parseCommand(const char *pinput, int len, train_t *pt)
{
    char *pstrs[10] = {0};
    int cnt = 0;
    splitString(pinput, " ", pstrs, 10, &cnt);
    pt->type = (CmdType)getCommandType(pstrs[0]);
    if (cnt > 1)
    {
        pt->len = strlen(pstrs[1]);
        strncpy(pt->buff, pstrs[1], pt->len);
    }
    return 0;
}
int recvn(int sockfd, void *buff, int len)
{
    int left = len;
    int ret = 0;
    char *pbuf = (char *)buff;
    while (left > 0)
    {
        ret = recv(sockfd, pbuf, left, 0);
        if (ret < 0)
        {
            perror("recv");
            return -1;
        }
        else if (ret == 0)
        {
            break;
        }
        pbuf += ret;
        left -= ret;
    }
    return len - left;
}
int sendn(int sockfd, const void *buff, int len)
{
    int left = len;
    int ret = 0;
    const char *pbuf = (const char *)buff;
    while (left > 0)
    {
        ret = send(sockfd, pbuf, left, 0);
        if (ret == -1)
        {
            perror("send");
            return -1;
        }
        pbuf += ret;
        left -= ret;
    }
    return len - left;
}
// static int userLogin1(int sockfd, train_t *pt)
// {
//     train_t t;
//     memset(&t, 0, sizeof(t));
//     while (true)
//     {
//         printf(USER_NAME);
//         char user[20] = {0};
//         int ret = read(STDIN_FILENO, user, sizeof(user));
//         user[ret - 1] = '\0';
//         t.len = strlen(user);
//         t.type = TASK_LOGIN_SECTION1;
//         strncpy(t.buff, user, t.len);
//         ret = sendn(sockfd, &t, 8 + t.len);
//         memset(&t, 0, sizeof(t));
//         ret = recvn(sockfd, &t.len, 4);
//         ret = recvn(sockfd, &t.type, 4);
//         if (t.type == TASK_LOGIN_SECTION1_RESP_ERROR)
//         {
//             printf("user name not exist.\n");
//             continue;
//         }
//         ret = recvn(sockfd, t.buff, t.len);
//         // printf("%s\n", t.buff);
//         break;
//     }
//     memcpy(pt, &t, sizeof(t));
//     return 0;
// }
// static int userLogin2(int sockfd, train_t *pt)
// {
//     int ret;
//     train_t t;
//     memset(&t, 0, sizeof(t));
//     while (true)
//     {
//         char *passwd = getpass(PASSWORD);
//         char *encrytped = crypt(passwd, pt->buff);
//         t.len = strlen(encrytped);
//         t.type = TASK_LOGIN_SECTION2;
//         strncpy(t.buff, encrytped, t.len);
//         ret = sendn(sockfd, &t, 8 + t.len);
//         memset(&t, 0, sizeof(t));
//         ret = recvn(sockfd, &t.len, 4);
//         ret = recvn(sockfd, &t.type, 4);
//         if (t.type == TASK_LOGIN_SECTION2_RESP_ERROR)
//         {
//             printf("sorry, password is not correct.\n");
//             continue;
//         }
//         else
//         {
//             ret = recvn(sockfd, t.buff, t.len);
//             printf("Login Success.\n");
//             printf("please input a command.\n");
//             fprintf(stderr, "%s", t.buff);
//             break;
//         }
//     }
//     memcpy(pt, &t, sizeof(t));
//     return 0;
// }
static int userLogin1(int sockfd, train_t *pt)
{
    memset(&login_msg, 0, sizeof(login_msg));
    train_t t;
    memset(&t, 0, sizeof(t));
    char passwd[30] = {0};
    while (true)
    {
        printf(USER_NAME);
        char user[20] = {0};
        int ret = read(STDIN_FILENO, user, sizeof(user));
        char *passw = getpass("请输入密码: ");
        strncpy(passwd, passw, strlen(passw) + 1);
        user[ret - 1] = '\0';
        strncpy(login_msg.name, user, strlen(user) + 1);
        t.len = strlen(user) + 1;
        t.type = LOGIN_PRE;
        strncpy(t.buff, user, t.len);
        ret = sendn(sockfd, &t, 8 + t.len);
        memset(&t, 0, sizeof(t));
        ret = recvn(sockfd, &t.len, 4);
        ret = recvn(sockfd, &t.type, 4);
        if (t.type == LOGIN_NO)
        {
            printf("账号已经存在, 请重新进行注册!\n");
            continue;
        }
        ret = recvn(sockfd, t.buff, t.len);
        if (t.type == LOGIN_POK)
        {
            strcpy(login_msg.token, t.buff); // 此时token是盐值
            strcpy(login_msg.passward, crypt(passwd, login_msg.token));
            t.len = sizeof(Zhuce);
            memcpy(t.buff, &login_msg, t.len);
            t.type = LOGIN_Q;
            ret = sendn(sockfd, &t, 8 + t.len);
            printf("注册成功\n");
            break;
        }
    }
    memcpy(pt, &t, sizeof(t));
    return 0;
}
static int userRegist2(int sockfd, train_t *pt)
{
    train_t t;
    memset(&t, 0, sizeof(t));
    char passwd[30] = {0};
    while (true)
    {
        printf(USER_NAME);
        char user[20] = {0};
        int ret = read(STDIN_FILENO, user, sizeof(user));
        char *passw = getpass("请输入密码: ");
        strncpy(passwd, passw, strlen(passw) + 1);
        user[ret - 1] = '\0';
        strncpy(login_msg.name, user, strlen(user) + 1);
        t.len = strlen(user) + 1;
        t.type = REGISTER_PRE;
        strncpy(t.buff, user, t.len);
        ret = sendn(sockfd, &t, 8 + t.len);
        memset(&t, 0, sizeof(t));
        ret = recvn(sockfd, &t.len, 4);
        ret = recvn(sockfd, &t.type, 4);
        if (t.type == REGISTER_NO)
        {
            printf("账号/密码错误，请重新登录\n");
            continue;
        }
        ret = recvn(sockfd, t.buff, t.len);
        if (t.type == REGISTER_POK)
        {
            strcpy(login_msg.passward, crypt(passwd, t.buff));
            sprintf(login_msg.token, "%s %s", login_msg.name, ctime(&now));
            t.len = sizeof(Zhuce);
            memcpy(t.buff, &login_msg, t.len);
            t.type = REGISTER_Q;
            ret = sendn(sockfd, &t, 8 + t.len);
            break;
        }
    }
    memcpy(pt, &t, sizeof(t));
    printf("登录成功\n");
    return 0;
}
int userLogin(int sockfd)
{
    int ret;
    train_t t;
    memset(&t, 0, sizeof(t));
    // v1版本
    //  userLogin1(sockfd, &t);
    //  userLogin2(sockfd, &t);
    userLogin1(sockfd, &t);
    userRegist2(sockfd, &t);
    return 0;
}
void putsCommand(int sockfd, train_t *pt)
{
    char filename[20] = {0};
    strcpy(filename, pt->buff);
    int fd = open(filename, O_RDWR);
    if (fd < 0)
    {
        perror("open");
        return;
    }
    struct stat st;
    memset(&st, 0, sizeof(st));
    fstat(fd, &st);
    printf("file length: %ld\n", st.st_size);
    int ret = sendn(sockfd, &st.st_size, sizeof(st.st_size));
    char buffer[1000] = {0};
    off_t cur;
    memset(&cur, 0, sizeof(cur));
    while (cur < st.st_size)
    {
        memset(buffer, 0, sizeof(buffer));
        ret = read(fd, buffer, sizeof(buffer));
        if (ret == 0)
        {
            break;
        }
        ret = sendn(sockfd, buffer, ret);
        cur += ret;
    }
    printf("file send over.\n");
    close(fd);
}